package com.tenton.netty.multicast;

import com.tenton.netty.config.NettyConfig;
import com.tenton.netty.pool.ThreadPool;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.InternetProtocolFamily;
import io.netty.channel.socket.nio.NioDatagramChannel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import java.net.*;
import java.util.Enumeration;

/**
 * @ClassName: DataRecvUdpServer
 * @Description: UDP Netty启动
 * @Author： tangdong
 * @Date： 2024/6/25
 */
@Component
@Slf4j
public class DataRecvUdpServer implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {
        ThreadPool.dataDealThreadPool.execute(() -> {
            DataRecvUdpServer.start(NettyConfig.multicastSubIp, NettyConfig.multicastSubPort);
        });
        log.info("UDP服务启动成功，绑定组播接收IP：{},端口为：{}", NettyConfig.multicastSubIp, NettyConfig.multicastSubPort);
    }

    public static void start(String groupIp, Integer groupPort) {
        // 组播地址
        InetSocketAddress groupAddress = new InetSocketAddress(groupIp, groupPort);

        EventLoopGroup group = new NioEventLoopGroup();

        try {
            NetworkInterface ni = NetworkInterface.getByInetAddress(InetAddress.getByName(NettyConfig.locIp));
            Enumeration<InetAddress> addresses = ni.getInetAddresses();

            InetAddress localAddress = null;
            while (addresses.hasMoreElements()) {
                InetAddress address = addresses.nextElement();
                if (address instanceof Inet4Address) {
                    localAddress = address;
                    System.out.println("网络接口名称为：" + ni.getName());
                    System.out.println("网卡接口地址：" + address.getHostAddress());
                }
            }

            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group)
                    .channelFactory(new ChannelFactory<NioDatagramChannel>() {
                        @Override
                        public NioDatagramChannel newChannel() {
                            return new NioDatagramChannel(InternetProtocolFamily.IPv4);
                        }
                    })
                    .localAddress(new InetSocketAddress(localAddress, groupPort))
                    .option(ChannelOption.IP_MULTICAST_IF, ni)
                    .option(ChannelOption.IP_MULTICAST_ADDR, InetAddress.getByName(NettyConfig.locIp))
                    .option(ChannelOption.SO_REUSEADDR, true)
                    .option(ChannelOption.SO_RCVBUF, 2048 * 1024)
                    .option(ChannelOption.SO_SNDBUF, 1024 * 1024)
                    .handler(new ChannelInitializer<NioDatagramChannel>() {
                        @Override
                        protected void initChannel(NioDatagramChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast(new NioEventLoopGroup(), new DataRecvHandler());

                        }
                    });

            NioDatagramChannel channel = (NioDatagramChannel) bootstrap.bind(groupAddress.getPort()).sync().channel();
            channel.joinGroup(groupAddress, ni).sync();
            channel.closeFuture().await();
        } catch (SocketException e) {
            throw new RuntimeException(e);
        } catch (UnknownHostException e) {
            throw new RuntimeException(e);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            group.shutdownGracefully();
        }

    }
}
